/* $Id: slideshow.jquery.js 22 2009-07-09 10:08:21Z geraldb $

Unobtrusive Accessible jQuery Slideshow.

Overview:
	jQuery.fn.slideshow()
	Slideshow for images (default) or other nodes via the slideSelector param
	Note: slides fade in on top of old slides.

Parameters:
	One parameter, an object with these properties:
	wait: (Float) How long to wait between slide flips (applies to wait time
		after unpausing as well).
		default: 5000
	fade: (String) Animation speed to fade images.
		default: 'slow'
	prepend: (String) Text to be prepended to classes on nodes.
		default: 'slideshow'
	controls: (Boolean) true = generate nodes to control slideshow.
		default: true

Usage:
	HTML:
	<div class="slideshow">
		<ul>
			<li><img .../></li>
			...
		</ul>
	</div>

	JAVASCRIPT:
	$('.slideshow').slideshow({wait: 3000, fade: 'normal'});

Author:
	gburns

TODO:
	Documentation
*/

(function($) {
$.fn.slideshow = function(settings) {
	var options = $.extend({
		wait: 5000,
		fade: 'slow',
		prepend: 'slideshow',
		slideSelector: 'img',
		controls: true
	}, settings || {});

	return this.each(function() {
		var current = null;
		var time_out = null;
		var fading = false;
		var is_clicking = false;
		var $container = $('ul:first', this);
		var $slides = $('> li', $container);
		var $this = $(this);
		var paused = false;

		$this
			.addClass(options.prepend + '_main');

		$container
			.css({position: 'relative'})
			.addClass(options.prepend + '_container');

		if ( $.browser.safari ) {
			$('img', $this)
				.bind('load', function() {
					this.complete = true;
				});
		}

		$slides.css({
			position: 'absolute',
			top: 0,
			left: 0,
			display: 'none'
			});
		$slides.slice(0,1).show();

		var next = function() {
			if ( fading ) return;
			if ( time_out ) {
				clearTimeout(time_out);
				time_out = null;
			}
			var prev = null;
			if ( current === null ) {
				current = 0;
			} else if ( current == $slides.length-1 ) {
				current = 0;
				prev = $slides.length-1;
			} else {
				prev = current;
				current++;
			}

			if ( prev !== null ) {
				var $slide = $($slides[current]).css({zIndex: 1});
				var $imgs;
				var complete = false;

				$imgs = $('img', $slide);
				if ( $imgs[0] ) {
					complete = true;
					$imgs.each(function() {
						if ( !this.complete ) {
							complete = false;
							return;
						}
					});
				}
				if ( !complete ) {
					current--;
				} else {
					$($slides[prev]).css({zIndex: 0});
					fading = true;
					$slide.fadeIn(options.fade, function() {
						$($slides[prev]).hide();
						fading = false;
					});
				}
			}
			if ( !paused ) time_out = setTimeout(next, options.wait);
		};

		var previous = function() {
			if ( fading ) return;
			if ( time_out ) {
				clearTimeout(time_out);
				time_out = null;
			}
			var prev = null;
			if ( current === null ) {
				current = 0;
			} else if ( current == 0 ) {
				current = $slides.length-1;
				prev = 0;
			} else {
				prev = current;
				current--;
			}

			if ( prev !== null ) {
				var $slide = $($slides[current]).css({zIndex: 100});
				var $imgs;
				var complete = false;

				$imgs = $('img', $slide);
				if ( $imgs[0] ) {
					complete = true;
					$imgs.each(function() {
						if ( !this.complete ) {
							complete = false;
							return;
						}
					});
				}

				if ( !complete ) {
					current++;
				} else {
					$($slides[prev]).css({zIndex: 0});
					fading = true;
					$slide.fadeIn(options.fade, function() {
						$($slides[prev]).hide();
						fading = false;
					});
				}
			}
			if ( !paused ) time_out = setTimeout(next, options.wait);
		};

		var pause = function() {
			if ( click_pause ) $this.addClass(options.prepend + '_paused');
			clearTimeout(time_out);
			time_out = null;
			paused = true;
		};

		var unpause = function() {
			$this.removeClass(options.prepend + '_paused');
			time_out = setTimeout(next, options.wait);
			paused = false;
		};

		var showing_all_slides = false;
		var view_all_toggle = function() {
			if ( !showing_all_slides ) {
				click_pause = true;
				pause();
				$slides.css({
					position: 'relative',
					top: null,
					left: null
					})
					.show('fast');
				$this.addClass(options.prepend + '_viewing_all');
				showing_all_slides = true;
			} else {
				showing_all_slides = false;
				$slides.css({
					position: 'absolute',
					top: 0,
					left: 0,
					display: 'none'
					});
				$($slides[current]).css({display: 'block'});
				$this.removeClass(options.prepend + '_viewing_all');
				click_pause = false;
				unpause();
			}
		};

		$slides
			.bind('mouseover', function() {
				if ( !click_pause ) pause();
			})
			.bind('mouseout', function() {
				if ( !click_pause ) unpause();
			});

		var click_pause = false;

		if ( options.controls ) {
			$controls = $('<div/>')
				.addClass(options.prepend + '_controls');

			$previous_link = $('<a href="javascript:;">Previous Image</a>')
				.bind('mouseover', function() {
					$(this).addClass('hover');
				})
				.bind('mouseout', function() {
					$(this).removeClass('hover');
				})
				.bind('mousedown', function() {
					is_clicking = true;
				})
				.bind('mouseup', function() {
					is_clicking = false;
				})
				.bind('focus', function() {
					if ( !is_clicking ) $(this).addClass('focus');
				})
				.bind('blur', function() {
					$(this).removeClass('focus');
				})
				.bind('click', previous);

			$previous_container = $('<p/>')
				.addClass(options.prepend + '_previous')
				.append($previous_link);

			$pause_link = $('<a href="javascript:;">Play/Pause</a>')
				.bind('mouseover', function() {
					$(this).addClass('hover');
				})
				.bind('mouseout', function() {
					$(this).removeClass('hover');
				})
				.bind('mousedown', function() {
					is_clicking = true;
				})
				.bind('mouseup', function() {
					is_clicking = false;
				})
				.bind('focus', function() {
					if ( !is_clicking ) $(this).addClass('focus');
				})
				.bind('blur', function() {
					$(this).removeClass('focus');
				})
				.bind('click', function() {
					if ( time_out ) {
						click_pause = true;
						pause();
					} else {
						click_pause = false;
						unpause();
					}
				});

			$pause_container = $('<p/>')
				.addClass(options.prepend + '_pause')
				.append($pause_link);

			$next_link = $('<a href="javascript:;">Next Image</a>')
				.bind('mouseover', function() {
					$(this).addClass('hover');
				})
				.bind('mouseout', function() {
					$(this).removeClass('hover');
				})
				.bind('mousedown', function() {
					is_clicking = true;
				})
				.bind('mouseup', function() {
					is_clicking = false;
				})
				.bind('focus', function() {
					if ( !is_clicking ) $(this).addClass('focus');
				})
				.bind('blur', function() {
					$(this).removeClass('focus');
				})
				.bind('click', next);

			$next_container = $('<p/>')
				.addClass(options.prepend + '_next')
				.append($next_link);

			$view_all_link = $('<a href="javascript:;">View All slides</a>')
				.bind('mouseover', function() {
					$(this).addClass('hover');
				})
				.bind('mouseout', function() {
					$(this).removeClass('hover');
				})
				.bind('mousedown', function() {
					is_clicking = true;
				})
				.bind('mouseup', function() {
					is_clicking = false;
				})
				.bind('focus', function() {
					if ( !is_clicking ) $(this).addClass('focus');
				})
				.bind('blur', function() {
					$(this).removeClass('focus');
				})
				.bind('click', function() {
					$view_all_container.hide();
					$collapse_container.show();
					view_all_toggle();
				});

			$view_all_container = $('<p/>')
				.addClass(options.prepend + '_view_all')
				.append($view_all_link);

			$collapse_link = $('<a href="javascript:;">Collapse Slides</a>')
				.bind('mouseover', function() {
					$(this).addClass('hover');
				})
				.bind('mouseout', function() {
					$(this).removeClass('hover');
				})
				.bind('mousedown', function() {
					is_clicking = true;
				})
				.bind('mouseup', function() {
					is_clicking = false;
				})
				.bind('focus', function() {
					if ( !is_clicking ) $(this).addClass('focus');
				})
				.bind('blur', function() {
					$(this).removeClass('focus');
				})
				.bind('click', function() {
					$view_all_container.show();
					$collapse_container.hide();
					view_all_toggle();
				});

			$collapse_container = $('<p/>')
				.addClass(options.prepend + '_collapse')
				.append($collapse_link)
				.hide();

			$controls
				.append($view_all_container)
				.append($collapse_container)
				.append($previous_container)
				.append($pause_container)
				.append($next_container);

			$this.append($controls);
		}

		time_out = setTimeout(next, options.wait);
	});
}
})(jQuery);